@file:Suppress("unused")

package com.sscl.easyble

import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothStatusCodes
import android.os.Build
import android.os.Handler
import androidx.annotation.RequiresApi
import com.sscl.easyble.defaultImpl.DefaultMultiBluetoothGattCallback
import com.sscl.easyble.enums.BlePhy
import com.sscl.easyble.enums.BlePhyOptions
import com.sscl.easyble.enums.bleconnect.BleConnectPhyMask
import com.sscl.easyble.enums.bleconnect.BleConnectTransport
import com.sscl.easyble.extensions.getCurrentPackageData
import com.sscl.easyble.extensions.getPageCount
import com.sscl.easyble.extensions.hasBluetoothConnectPermission
import com.sscl.easyble.extensions.startConnectTimeoutTimer
import com.sscl.easyble.interfaces.connections.OnBleConnectStateChangedListener
import com.sscl.easyble.interfaces.connections.OnCharacteristicDataOptionsListener
import com.sscl.easyble.interfaces.connections.OnDescriptorDataOptionListener
import com.sscl.easyble.interfaces.connections.OnLargeCharacteristicDataWriteListener
import com.sscl.easyble.interfaces.connections.OnLargeCharacteristicDataWriteWithNotificationListener
import com.sscl.easyble.interfaces.connections.OnMtuChangedListener
import com.sscl.easyble.interfaces.connections.OnPhyOptionsListener
import com.sscl.easyble.interfaces.connections.OnReadRemoteRssiListener
import com.sscl.easyble.interfaces.connections.OnReliableWriteCompletedListener
import com.sscl.easyble.variable.GlobalConnectVariable
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.util.UUID
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.TimeUnit

class BleConnector internal constructor() {

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 静态声明
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    companion object {
        private const val TAG = "BleConnector"
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 属性声明
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /* * * * * * * * * * * * * * * * * * * 可变属性 * * * * * * * * * * * * * * * * * * */

    /**
     * 连接超时时间
     */
    private var connectTimeOut: Long = GlobalConnectVariable.CONNECT_TIME_OUT

    /**
     * 连接超时时间单位
     */
    private var connectTimeOutUnit = GlobalConnectVariable.connectTimeOutUnit

    /* * * * * * * * * * * * * * * * * * * 常量属性 * * * * * * * * * * * * * * * * * * */

    private val defaultMultiBluetoothGattCallback = DefaultMultiBluetoothGattCallback()

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 公开方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 设置连接超时时间
     * @param timeOut 连接超时时间
     * @param timeOutUnit 连接超时时间单位
     */
    fun setConnectTimeOut(timeOut: Long, timeOutUnit: TimeUnit): BleConnector {
        connectTimeOut = timeOut
        connectTimeOutUnit = timeOutUnit
        return this
    }

    /**
     * 连接设备
     * @param device 设备
     * @param onBleConnectStateChangedListener 连接状态监听器
     * @param autoConnect 是否自动连接
     * @param transport 传输类型
     * @param phyMask 物理层掩码
     * @param handler 处理程序
     */
    fun connectDevice(
        device: BluetoothDevice,
        onBleConnectStateChangedListener: OnBleConnectStateChangedListener?,
        autoConnect: Boolean = false,
        transport: BleConnectTransport? = null,
        phyMask: BleConnectPhyMask? = null,
        handler: Handler? = null,
    ): Boolean {
        val address = device.address
        val gatt = createGatt(device, autoConnect, transport, phyMask, handler) ?: return false
        GlobalConnectVariable.gattList[address] = gatt
        GlobalConnectVariable.bluetoothGattConnectStateChangedListenerList[address] =
            onBleConnectStateChangedListener
        address.startConnectTimeoutTimer(connectTimeOut, connectTimeOutUnit)
        return true
    }

    /**
     *  连接设备
     *  @param address 设备地址
     *  @param onBleConnectStateChangedListener 连接状态监听器
     *  @param autoConnect 是否自动连接
     *  @param transport 传输类型
     *  @param phyMask 物理层掩码
     *  @param handler 处理程序
     */
    fun connectDevice(
        address: String,
        onBleConnectStateChangedListener: OnBleConnectStateChangedListener?,
        autoConnect: Boolean = false,
        transport: BleConnectTransport? = null,
        phyMask: BleConnectPhyMask? = null,
        handler: Handler? = null
    ): Boolean {
        val device = BleManager.bluetoothAdapter?.getRemoteDevice(address) ?: return false
        return connectDevice(
            device, onBleConnectStateChangedListener, autoConnect, transport, phyMask, handler
        )
    }

    /**
     *  断开GATT连接
     *  @param address 设备地址
     *  @return 是否执行成功
     */
    fun disconnect(address: String): Boolean {
        if (!GlobalConnectVariable.gattList.containsKey(address)) {
            Logger.log(TAG, "未与设备建立过连接，尝试获取系统内的GATT对象")
            Logger.log(
                TAG,
                "device is not connected in cache.Trying to get the GATT object from the system"
            )
            BleManager.bluetoothAdapter?.getRemoteDevice(address)?.let {
                val bluetoothGatt = createGatt(it)
                GlobalConnectVariable.gattList[address] = bluetoothGatt ?: return false
                return disconnect(address)
            }
            return false
        }
        val succeed = GlobalConnectVariable.gattList[address]?.disconnect() != null
        if (succeed) {
            GlobalConnectVariable.connectedStateList[address] = false
        }
        return succeed
    }

    /**
     * 断开GATT连接
     * @param device 设备
     * @return 是否执行成功
     */
    fun disconnect(device: BluetoothDevice): Boolean {
        return disconnect(device.address)
    }

    /**
     *  断开所有GATT连接
     */
    fun disconnectAll() {
        val keys = GlobalConnectVariable.gattList.keys
        for (address in keys) {
            disconnect(address)
        }
    }

    /**
     * 关闭GATT
     * @param address 设备地址
     */
    fun closeGatt(address: String) {
        if (!GlobalConnectVariable.gattList.containsKey(address)) {
            Logger.log(TAG, "未与设备建立过连接，尝试获取系统内的GATT对象")
            Logger.log(TAG, "device is not connected.Trying to get the GATT object from the system")
            BleManager.bluetoothAdapter?.getRemoteDevice(address)?.let {
                val bluetoothGatt = createGatt(it)
                GlobalConnectVariable.gattList[address] = bluetoothGatt ?: return
                closeGatt(address)
            }
            return
        }
        val bluetoothGatt = GlobalConnectVariable.gattList.remove(address)
        GlobalConnectVariable.connectedStateList.remove(address)
        bluetoothGatt?.close()
    }

    /**
     * 关闭GATT
     * @param device 设备
     */
    fun closeGatt(device: BluetoothDevice) {
        return closeGatt(device.address)
    }

    /**
     *  关闭所有GATT连接
     */
    fun closeAllGatt() {
        while (true) {
            if (GlobalConnectVariable.gattList.isEmpty()) {
                break
            }
            val address = GlobalConnectVariable.gattList.keys.first()
            disconnect(address)
            closeGatt(address)
        }
    }

    /**
     * 判断设备是否连接
     * @param address 设备地址
     * @return 是否连接
     */
    fun isDeviceConnected(address: String): Boolean {
        return GlobalConnectVariable.connectedStateList[address] == true
    }

    /**
     * 判断设备是否连接
     * @param device 设备
     * @return 是否连接
     */
    fun isDeviceConnected(device: BluetoothDevice): Boolean {
        return isDeviceConnected(device.address)
    }

    /**
     * 获取设备的全部服务
     * @param address 设备地址
     * @return 服务列表
     */
    fun getServices(address: String): List<BluetoothGattService>? {
        return GlobalConnectVariable.gattList[address]?.services
    }

    /**
     * 获取设备的全部服务
     * @param device 设备
     * @return 服务列表
     */
    fun getServices(device: BluetoothDevice): List<BluetoothGattService>? {
        return getServices(device.address)
    }

    /**
     * 根据UUID 获取指定的服务
     *
     * @param address 设备地址
     * @param uuid UUID
     * @return BluetoothGattService
     */
    fun getService(address: String, uuid: UUID): BluetoothGattService? {
        return GlobalConnectVariable.gattList[address]?.getService(uuid)
    }

    /**
     * 根据UUID 获取指定的服务
     *
     * @param device 设备
     * @param uuid UUID
     * @return BluetoothGattService
     */
    fun getService(device: BluetoothDevice, uuid: UUID): BluetoothGattService? {
        return getService(device.address, uuid)
    }

    /**
     * 根据UUID 获取指定的服务
     *
     * @param address 设备地址
     * @param uuidString UUID字符串
     * @return BluetoothGattService
     */
    fun getService(address: String, uuidString: String): BluetoothGattService? {
        return getService(address, UUID.fromString(uuidString))
    }

    /**
     * 根据UUID 获取指定的服务
     *
     * @param device 设备
     * @param uuidString UUID字符串
     * @return BluetoothGattService
     */
    fun getService(device: BluetoothDevice, uuidString: String): BluetoothGattService? {
        return getService(device.address, uuidString)
    }

    /**
     * 获取设备的特征
     * @param bluetoothGattService BluetoothGattService
     * @param uuid UUID
     * @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        bluetoothGattService: BluetoothGattService, uuid: UUID
    ): BluetoothGattCharacteristic? {
        return bluetoothGattService.getCharacteristic(uuid)
    }

    /**
     *  获取设备的特征
     *  @param bluetoothGattService BluetoothGattService
     *  @param uuidString UUID字符串
     *  @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        bluetoothGattService: BluetoothGattService, uuidString: String
    ): BluetoothGattCharacteristic? {
        return getCharacteristic(bluetoothGattService, UUID.fromString(uuidString))
    }

    /**
     * 获取设备的特征
     * @param address 设备地址
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        address: String, serviceUUID: UUID, characteristicUUID: UUID
    ): BluetoothGattCharacteristic? {
        return getService(address, serviceUUID)?.getCharacteristic(characteristicUUID)
    }

    /**
     * 获取设备的特征
     * @param device 设备地址
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        device: BluetoothDevice, serviceUUID: UUID, characteristicUUID: UUID
    ): BluetoothGattCharacteristic? {
        return getCharacteristic(
            device.address, serviceUUID, characteristicUUID
        )
    }

    /**
     * 获取设备的特征
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUuidString 特征UUID字符串
     * @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        address: String, serviceUUIDString: String, characteristicUuidString: String
    ): BluetoothGattCharacteristic? {
        return getCharacteristic(
            address, UUID.fromString(serviceUUIDString), UUID.fromString(characteristicUuidString)
        )
    }

    /**
     * 获取设备的特征
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUuidString 特征UUID字符串
     * @return BluetoothGattCharacteristic
     */
    fun getCharacteristic(
        device: BluetoothDevice, serviceUUIDString: String, characteristicUuidString: String
    ): BluetoothGattCharacteristic? {
        return getCharacteristic(
            device.address, serviceUUIDString, characteristicUuidString
        )
    }

    /**
     * 请求读取设备描述数据
     * @param address 设备地址
     * @param descriptor 描述
     * @return 是否执行成功
     */
    fun readDescriptorData(address: String, descriptor: BluetoothGattDescriptor): Boolean {
        return GlobalConnectVariable.gattList[address]?.readDescriptor(descriptor) ?: false
    }

    /**
     * 请求读取设备描述数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param descriptorUUIDString 描述UUID字符串
     * @return 是否执行成功
     */
    fun readDescriptorData(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String
    ): Boolean {
        val characteristic =
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString) ?: return false
        val descriptor =
            characteristic.getDescriptor(UUID.fromString(descriptorUUIDString)) ?: return false
        return readDescriptorData(address, descriptor)
    }

    /**
     *  读取描述数据
     *  @param device 设备
     *  @param descriptor 描述
     *  @return 是否执行成功
     */
    fun readDescriptorData(device: BluetoothDevice, descriptor: BluetoothGattDescriptor): Boolean {
        return readDescriptorData(device.address, descriptor)
    }

    /**
     *  读取描述数据
     *  @param device 设备
     *  @param serviceUUIDString 服务UUID字符串
     *  @param characteristicUUIDString 特征UUID字符串
     *  @param descriptorUUIDString 描述UUID字符串
     *  @return 是否执行成功
     */
    fun readDescriptorData(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String
    ): Boolean {
        val characteristic =
            getCharacteristic(device, serviceUUIDString, characteristicUUIDString) ?: return false
        val descriptor =
            characteristic.getDescriptor(UUID.fromString(descriptorUUIDString)) ?: return false
        return readDescriptorData(device, descriptor)
    }

    /**
     * 写入描述数据
     * @param address 设备地址
     * @param descriptor 描述
     * @param byteArray 数据
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他则返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeDescriptorData(
        address: String, descriptor: BluetoothGattDescriptor, byteArray: ByteArray
    ): Int {
        return (GlobalConnectVariable.gattList[address]?.writeDescriptor(descriptor, byteArray)
            ?: BluetoothStatusCodes.ERROR_UNKNOWN)
    }

    /**
     * 写入描述数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param descriptorUUIDString 描述UUID字符串
     * @param byteArray 数据
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他则返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeDescriptorData(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String,
        byteArray: ByteArray
    ): Int {
        val characteristic = getCharacteristic(address, serviceUUIDString, characteristicUUIDString)
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        val descriptor = characteristic.getDescriptor(UUID.fromString(descriptorUUIDString))
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        return writeDescriptorData(address, descriptor, byteArray)
    }

    /**
     * 写入描述数据
     * @param device 设备
     * @param descriptor 描述
     * @param byteArray 数据
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他则返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeDescriptorData(
        device: BluetoothDevice, descriptor: BluetoothGattDescriptor, byteArray: ByteArray
    ): Int {
        return writeDescriptorData(device, descriptor, byteArray)
    }

    /**
     * 写入描述数据
     * @param device 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param descriptorUUIDString 描述UUID字符串
     * @param byteArray 数据
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他则返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeDescriptorData(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String,
        byteArray: ByteArray
    ): Int {
        val characteristic = getCharacteristic(device, serviceUUIDString, characteristicUUIDString)
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        val descriptor = characteristic.getDescriptor(UUID.fromString(descriptorUUIDString))
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        return writeDescriptorData(device, descriptor, byteArray)
    }

    /**
     * 写入描述数据
     * 在[Build.VERSION_CODES.TIRAMISU]中声明被弃用
     * 请使用[BleConnector.writeCompatDescriptorData]替代
     * 在minSdkVersion大于[Build.VERSION_CODES.TIRAMISU]的版本下，建议使用[BleConnector.writeDescriptorData]
     *
     * @param address 设备地址
     * @param descriptor 描述符
     *
     *  @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatDescriptorData"))
    fun writeDescriptorDataOld(
        address: String, descriptor: BluetoothGattDescriptor
    ): Boolean {
        @Suppress("DEPRECATION") return GlobalConnectVariable.gattList[address]?.writeDescriptor(
            descriptor
        ) ?: false
    }

    /**
     * 写入描述数据
     * 在[Build.VERSION_CODES.TIRAMISU]中声明被弃用
     * 请使用[BleConnector.writeCompatDescriptorData]替代
     * 在minSdkVersion大于[Build.VERSION_CODES.TIRAMISU]的版本下，建议使用[BleConnector.writeDescriptorData]
     *
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param descriptorUUIDString 描述UUID字符串
     * @param byteArray 数据
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatDescriptorData"))
    fun writeDescriptorDataOld(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        val characteristic =
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString) ?: return false
        val descriptor =
            characteristic.getDescriptor(UUID.fromString(descriptorUUIDString)) ?: return false
        @Suppress("DEPRECATION")
        descriptor.value = byteArray
        @Suppress("DEPRECATION") return writeDescriptorDataOld(address, descriptor)
    }


    /**
     * 写入描述数据
     * 在[Build.VERSION_CODES.TIRAMISU]中声明被弃用
     * 请使用[BleConnector.writeCompatDescriptorData]替代
     * 在minSdkVersion大于[Build.VERSION_CODES.TIRAMISU]的版本下，建议使用[BleConnector.writeDescriptorData]
     *
     * @param device 设备
     * @param descriptor 描述符
     *
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatDescriptorData"))
    fun writeDescriptorDataOld(
        device: BluetoothDevice, descriptor: BluetoothGattDescriptor
    ): Boolean {
        @Suppress("DEPRECATION") return writeDescriptorDataOld(device.address, descriptor)
    }


    /**
     * 写入描述数据
     * 在[Build.VERSION_CODES.TIRAMISU]中声明被弃用
     * 请使用[BleConnector.writeCompatDescriptorData]替代
     * 在minSdkVersion大于[Build.VERSION_CODES.TIRAMISU]的版本下，建议使用[BleConnector.writeDescriptorData]
     *
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param descriptorUUIDString 描述UUID字符串
     * @param byteArray 数据
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatDescriptorData"))
    fun writeDescriptorDataOld(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        descriptorUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        val characteristic =
            getCharacteristic(device, serviceUUIDString, characteristicUUIDString) ?: return false
        val descriptor =
            characteristic.getDescriptor(UUID.fromString(descriptorUUIDString)) ?: return false
        @Suppress("DEPRECATION")
        descriptor.value = byteArray
        @Suppress("DEPRECATION") return writeDescriptorDataOld(device, descriptor)
    }

    /**
     * 写入描述数据
     * @param address 设备地址
     * @param descriptor 描述
     * @param byteArray 数据
     * @return 是否执行成功
     */
    @Suppress("DEPRECATION")
    fun writeCompatDescriptorData(
        address: String, descriptor: BluetoothGattDescriptor, byteArray: ByteArray
    ): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            return writeDescriptorData(
                address, descriptor, byteArray
            ) == BluetoothStatusCodes.SUCCESS
        } else {
            descriptor.value = byteArray
            writeDescriptorDataOld(address, descriptor)
        }
    }

    /**
     * 写入描述数据
     * @param device 设备
     * @param descriptor 描述
     * @param byteArray 数据
     * @return 是否执行成功
     */
    fun writeCompatDescriptorData(
        device: BluetoothDevice, descriptor: BluetoothGattDescriptor, byteArray: ByteArray
    ): Boolean {
        return writeCompatDescriptorData(device.address, descriptor, byteArray)
    }

    /**
     * 读取特征数据
     * @param address 设备地址
     * @param characteristic 特征
     * @return 是否执行成功
     */
    fun readCharacteristicData(
        address: String, characteristic: BluetoothGattCharacteristic
    ): Boolean {
        return GlobalConnectVariable.gattList[address]?.readCharacteristic(characteristic) ?: false
    }

    /**
     * 读取特征数据
     * @param device 设备
     * @param characteristic 特征
     * @return 是否执行成功
     */
    fun readCharacteristicData(
        device: BluetoothDevice, characteristic: BluetoothGattCharacteristic
    ): Boolean {
        return readCharacteristicData(device.address, characteristic)
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param characteristic 特征
     * @param byteArray 数据
     * @param writeType 写入类型
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeCharacteristicData(
        address: String,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        writeType: Int
    ): Int {
        return GlobalConnectVariable.gattList[address]?.writeCharacteristic(
            characteristic, byteArray, writeType
        ) ?: BluetoothStatusCodes.ERROR_UNKNOWN
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 数据
     * @param writeType 写入类型
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeCharacteristicData(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        writeType: Int
    ): Int {
        val characteristic = getCharacteristic(address, serviceUUIDString, characteristicUUIDString)
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        return writeCharacteristicData(address, characteristic, byteArray, writeType)
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param characteristic 特征
     * @param byteArray 数据
     * @param writeType 写入类型
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeCharacteristicData(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        writeType: Int
    ): Int {
        return writeCharacteristicData(device.address, characteristic, byteArray, writeType)
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 数据
     * @param writeType 写入类型
     * @return 成功返回[BluetoothStatusCodes.SUCCESS] 其他返回错误码
     */
    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    fun writeCharacteristicData(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        writeType: Int
    ): Int {
        val characteristic = getCharacteristic(device, serviceUUIDString, characteristicUUIDString)
            ?: return BluetoothStatusCodes.ERROR_UNKNOWN
        return writeCharacteristicData(device, characteristic, byteArray, writeType)
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param characteristic 特征
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatCharacteristicData"))
    fun writeCharacteristicDataOld(
        address: String, characteristic: BluetoothGattCharacteristic
    ): Boolean {
        @Suppress("DEPRECATION") return GlobalConnectVariable.gattList[address]?.writeCharacteristic(
            characteristic
        ) ?: false
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatCharacteristicData"))
    fun writeCharacteristicDataOld(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        val characteristic =
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString) ?: return false
        @Suppress("DEPRECATION")
        characteristic.value = byteArray
        @Suppress("DEPRECATION") return writeCharacteristicDataOld(address, characteristic)
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param characteristic 特征
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatCharacteristicData"))
    fun writeCharacteristicDataOld(
        device: BluetoothDevice, characteristic: BluetoothGattCharacteristic
    ): Boolean {
        @Suppress("DEPRECATION") return writeCharacteristicDataOld(device.address, characteristic)
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    @Deprecated("Deprecated in Java", ReplaceWith("writeCompatCharacteristicData"))
    fun writeCharacteristicDataOld(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        val characteristic =
            getCharacteristic(device, serviceUUIDString, characteristicUUIDString) ?: return false
        @Suppress("DEPRECATION")
        characteristic.value = byteArray
        @Suppress("DEPRECATION") return writeCharacteristicDataOld(device, characteristic)
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param characteristic 特征
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    fun writeCompatCharacteristicData(
        address: String, characteristic: BluetoothGattCharacteristic, byteArray: ByteArray
    ): Boolean {
        val writeType = characteristic.writeType
        Logger.log(TAG, "writeType $writeType")
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            val cache = writeCharacteristicData(
                address, characteristic, byteArray, characteristic.writeType
            ) == BluetoothStatusCodes.SUCCESS
            Logger.log(TAG, "writeCharacteristicData result $cache")
            cache
        } else {
            @Suppress("DEPRECATION")
            characteristic.value = byteArray
            @Suppress("DEPRECATION")
            val cache = writeCharacteristicDataOld(address, characteristic)
            Logger.log(TAG, "writeCharacteristicDataOld result $cache")
            cache
        }
    }

    /**
     * 写入特征数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    fun writeCompatCharacteristicData(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        return writeCompatCharacteristicData(
            address,
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString) ?: return false,
            byteArray
        )
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param characteristic 特征
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    fun writeCompatCharacteristicData(
        device: BluetoothDevice, characteristic: BluetoothGattCharacteristic, byteArray: ByteArray
    ): Boolean {
        return writeCompatCharacteristicData(device.address, characteristic, byteArray)
    }

    /**
     * 写入特征数据
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 写入数据
     * @return 是否执行成功
     */
    fun writeCompatCharacteristicData(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray
    ): Boolean {
        return writeCompatCharacteristicData(
            device,
            getCharacteristic(device, serviceUUIDString, characteristicUUIDString) ?: return false,
            byteArray
        )
    }

    /**
     * 开启消息通知
     * @param address 设备地址
     * @param characteristic 特征
     * @param enable 是否开启
     * @return 是否执行成功
     */
    fun enableNotification(
        address: String,
        characteristic: BluetoothGattCharacteristic,
        enable: Boolean
    ): Boolean {
        val result: Boolean
        if (!hasBluetoothConnectPermission()) {
            Logger.log(TAG, "开启消息通知:没有蓝牙连接权限,直接返回false")
            result = false
        } else {
            if (!BleManager.characteristicCanNotify(characteristic)) {
                result = false
            } else {
                val cacheResult =
                    GlobalConnectVariable.gattList[address]?.setCharacteristicNotification(
                        characteristic, enable
                    ) ?: false
                if (!cacheResult) {
                    result = false
                } else {
                    val bluetoothGattDescriptor =
                        characteristic.getDescriptor(UUID.fromString(InternalConstants.CLIENT_CHARACTERISTIC_CONFIG))
                    if (bluetoothGattDescriptor == null) {
                        result = true
                    } else {
                        result = if (enable) {
                            writeCompatDescriptorData(
                                address,
                                bluetoothGattDescriptor,
                                BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
                            )
                        } else {
                            writeCompatDescriptorData(
                                address,
                                bluetoothGattDescriptor,
                                BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
                            )
                        }
                    }
                }
            }
        }
        Logger.log(TAG, "打开通知 enable $enable result $result")
        return result
    }

    /**
     * 开启消息通知
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param enable 是否开启通知
     * @return 是否成功
     */
    fun enableNotification(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        enable: Boolean
    ): Boolean {
        val characteristic =
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString) ?: return false
        return enableNotification(address, characteristic, enable)
    }

    /**
     *  开启消息通知
     *  @param address 设备地址
     *  @param serviceUUID 服务UUID
     *  @param characteristicUUID 特征UUID
     *  @param enable 是否开启通知
     *  @return 是否成功
     */
    fun enableNotification(
        address: String, serviceUUID: UUID, characteristicUUID: UUID, enable: Boolean
    ): Boolean {
        val characteristic =
            getCharacteristic(address, serviceUUID, characteristicUUID) ?: return false
        return enableNotification(address, characteristic, enable)
    }

    /**
     * 开启消息通知
     * @param device 设备
     * @param characteristic 特征
     * @param enable 是否开启通知
     * @return 是否成功
     */
    fun enableNotification(
        device: BluetoothDevice, characteristic: BluetoothGattCharacteristic, enable: Boolean
    ): Boolean {
        return enableNotification(device.address, characteristic, enable)
    }

    /**
     * 开启消息通知
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param enable 是否开启通知
     * @return 是否成功
     */
    fun enableNotification(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        enable: Boolean
    ): Boolean {
        val characteristic =
            getCharacteristic(device, serviceUUIDString, characteristicUUIDString) ?: return false
        return enableNotification(device.address, characteristic, enable)
    }

    /**
     * 开启通知
     * @param device 设备
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @param enable 是否开启通知
     * @return 是否成功
     */
    fun enableNotification(
        device: BluetoothDevice, serviceUUID: UUID, characteristicUUID: UUID, enable: Boolean
    ): Boolean {
        val characteristic =
            getCharacteristic(device.address, serviceUUID, characteristicUUID) ?: return false
        return enableNotification(device, characteristic, enable)
    }

    /**
     * 设置描述数据操作监听
     * @param address 设备地址
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnDescriptorDataOptionListener(
        address: String, listener: OnDescriptorDataOptionListener?
    ): BleConnector {
        if (listener != null) {
            GlobalConnectVariable.onDescriptorDataOptionListenerList[address] = listener
        } else {
            GlobalConnectVariable.onDescriptorDataOptionListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置描述数据操作监听
     * @param device 设备
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnDescriptorDataOptionListener(
        device: BluetoothDevice, listener: OnDescriptorDataOptionListener?
    ): BleConnector {
        return setOnDescriptorDataOptionListener(device.address, listener)
    }

    /**
     * 设置可靠数据写入完成回调
     * @param address 设备地址
     * @param listener 回调
     * @return 本类实例
     */
    fun setOnReliableWriteCompletedListener(
        address: String,
        listener: OnReliableWriteCompletedListener?
    ): BleConnector {
        if (listener != null) {
            GlobalConnectVariable.onReliableWriteCompletedListenerList[address] = listener
        } else {
            GlobalConnectVariable.onReliableWriteCompletedListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置可靠数据写入完成回调
     * @param device 设备
     * @param listener 回调
     * @return 本类实例
     */
    fun setOnReliableWriteCompletedListener(
        device: BluetoothDevice,
        listener: OnReliableWriteCompletedListener?
    ): BleConnector {
        return setOnReliableWriteCompletedListener(device.address, listener)
    }

    /**
     * 设置特征数据操作监听
     * @param address 设备地址
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnCharacteristicDataOptionsListener(
        address: String, listener: OnCharacteristicDataOptionsListener?
    ): BleConnector {
        if (listener != null) {
            GlobalConnectVariable.onCharacteristicDataOptionsListenerList[address] = listener
        } else {
            GlobalConnectVariable.onCharacteristicDataOptionsListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置特征数据操作监听
     * @param device 设备
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnCharacteristicDataOptionsListener(
        device: BluetoothDevice, listener: OnCharacteristicDataOptionsListener?
    ): BleConnector {
        return setOnCharacteristicDataOptionsListener(device.address, listener)
    }

    /**
     * 设置读取远程RSSI监听
     * @param address 设备地址
     * @param listener 监听器
     * @return 本类实例
     */
    fun setonReadRemoteRssiListener(
        address: String, listener: OnReadRemoteRssiListener?
    ): BleConnector = apply {
        if (listener != null) {
            GlobalConnectVariable.onReadRemoteRssiListenerList[address] = listener
        } else {
            GlobalConnectVariable.onReadRemoteRssiListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置读取远程RSSI监听
     * @param device 设备
     * @param listener 监听器
     * @return 本类实例
     */
    fun setonReadRemoteRssiListener(
        device: BluetoothDevice, listener: OnReadRemoteRssiListener?
    ): BleConnector = apply {
        return setonReadRemoteRssiListener(device.address, listener)
    }

    /**
     * 设置MTU变化监听
     * @param address 设备地址
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnMtuChangedListener(address: String, listener: OnMtuChangedListener?): BleConnector {
        if (listener != null) {
            GlobalConnectVariable.onMtuChangedListenerList[address] = listener
        } else {
            GlobalConnectVariable.onMtuChangedListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置MTU变化监听
     * @param device 设备
     * @param listener 监听器
     * @return 本类实例
     */
    fun setOnMtuChangedListener(
        device: BluetoothDevice, listener: OnMtuChangedListener?
    ): BleConnector {
        return setOnMtuChangedListener(device.address, listener)
    }

    /**
     * 设置phy监听
     * @param address 设备地址
     * @param listener 监听器
     * @return 本类实例
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun setOnPhyOptionsListener(address: String, listener: OnPhyOptionsListener?): BleConnector {
        if (listener != null) {
            GlobalConnectVariable.onPhyOptionsListenerList[address] = listener
        } else {
            GlobalConnectVariable.onPhyOptionsListenerList.remove(address)
        }
        return this
    }

    /**
     * 设置phy监听
     * @param device 设备
     * @param listener 监听器
     * @return 本类实例
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun setOnPhyOptionsListener(
        device: BluetoothDevice, listener: OnPhyOptionsListener?
    ): BleConnector {
        return setOnPhyOptionsListener(device.address, listener)
    }

    /**
     * 写入大量数据
     * @param address 设备地址
     * @param characteristic 特征
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        address: String,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        val runnable = Runnable {
            val pageCount = byteArray.getPageCount(singlePackMaxLength)
            val targetIndex = pageCount - 1
            var currentIndex = 0
            var tryCount = 0
            var currentSendData: ByteArray? = null
            val cacheListener =
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList.remove(address)
            val listener = object : OnCharacteristicDataOptionsListener {
                override fun onCharacteristicRead(
                    address: String,
                    characteristic: BluetoothGattCharacteristic,
                    value: ByteArray,
                    gattState: Int
                ) {

                }

                override fun onCharacteristicWrite(
                    address: String, characteristic: BluetoothGattCharacteristic, gattState: Int
                ) {
                    if (gattState != BluetoothGatt.GATT_SUCCESS) {
                        GlobalConnectVariable.writeLargeDataKeepList[address] = false
                        InternalConstants.handler.post {
                            callback?.writeDataError(
                                currentIndex,
                                targetIndex,
                                gattState,
                                currentSendData ?: byteArrayOf()
                            )
                        }
                        return
                    }
                    InternalConstants.handler.post {
                        callback?.sendProgressChanged(
                            currentIndex, targetIndex, currentSendData ?: byteArrayOf()
                        )
                        currentIndex++
                        GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
                    }
                }

                override fun onCharacteristicNotify(
                    address: String, characteristic: BluetoothGattCharacteristic, value: ByteArray
                ) {

                }
            }
            GlobalConnectVariable.onCharacteristicDataOptionsListenerList[address] = listener
            GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
            InternalConstants.handler.post {
                callback?.sendStarted()
            }
            GlobalConnectVariable.writeLargeDataKeepList[address] = true
            while (true) {
                if (GlobalConnectVariable.writeLargeDataKeepList[address] != true) {
                    break
                }
                if (GlobalConnectVariable.writeLargeDataContinueFlagList[address] != true) {
                    continue
                }
                GlobalConnectVariable.writeLargeDataContinueFlagList[address] = false
                currentSendData =
                    byteArray.getCurrentPackageData(currentIndex, pageCount, singlePackMaxLength)
                if (currentSendData == null) {
                    InternalConstants.handler.post {
                        callback?.sendFinish()
                    }
                    break
                }
                val succeed =
                    writeCompatCharacteristicData(address, characteristic, currentSendData)
                if (!succeed) {
                    if (tryCount <= maxTryCount) {
                        tryCount++
                        GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
                        continue
                    }
                    InternalConstants.handler.post {
                        callback?.sendFailed(currentIndex, targetIndex, currentSendData)
                    }
                    break
                }
            }
            if (cacheListener != null) {
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList[address] =
                    cacheListener
            } else {
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList.remove(address)
            }
            GlobalConnectVariable.writeLargeDataContinueFlagList.remove(address)
            GlobalConnectVariable.writeLargeDataKeepList.remove(address)
        }
        InternalConstants.threadFactory.newThread(runnable).start()
    }

    /**
     * 写入大量数据
     * @param address 设备地址
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        address: String,
        serviceUUID: UUID,
        characteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        val characteristic =
            getCharacteristic(address, serviceUUID, characteristicUUID)
        if (characteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic $characteristicUUID in service $serviceUUID"
            )
            callback?.startFailed()
            return
        }
        writeLargeCharacteristicData(
            address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxTryCount
        )
    }

    /**
     * 写入大量数据
     * @param address 设备地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        val characteristic =
            getCharacteristic(address, serviceUUIDString, characteristicUUIDString)
        if (characteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic $characteristicUUIDString in service $serviceUUIDString"
            )
            callback?.startFailed()
            return
        }
        writeLargeCharacteristicData(
            address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxTryCount
        )
    }

    /**
     * 写入大量数据
     * @param device 设备
     * @param characteristic 特征
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        writeLargeCharacteristicData(
            device.address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxTryCount
        )
    }

    /**
     * 写入大量数据
     * @param device 设备
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        device: BluetoothDevice,
        serviceUUID: UUID,
        characteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        val characteristic = getCharacteristic(device, serviceUUID, characteristicUUID)
        if (characteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic $characteristicUUID in service $serviceUUID"
            )
            callback?.startFailed()
            return
        }
        writeLargeCharacteristicData(
            device.address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxTryCount
        )
    }

    /**
     * 写入大量数据
     * @param device 设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxTryCount 最大尝试次数，默认3
     */
    fun writeLargeCharacteristicData(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteListener? = null,
        singlePackMaxLength: Int = 20,
        maxTryCount: Int = 3
    ) {
        val characteristic = getCharacteristic(device, serviceUUIDString, characteristicUUIDString)
        if (characteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic $characteristicUUIDString in service $serviceUUIDString"
            )
            callback?.startFailed()
            return
        }
        writeLargeCharacteristicData(
            device.address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxTryCount
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param address 设备地址
     * @param writeDataCharacteristic 写入数据特征
     * @param notificationCharacteristic 通知特征
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度，默认20
     * @param maxSendTryCount 最大尝试次数，默认3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认1000,单位:ms
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        writeDataCharacteristic: BluetoothGattCharacteristic,
        notificationCharacteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        if (!BleManager.characteristicCanNotify(notificationCharacteristic)) {
            callback.sendIntercept(0, 0, byteArrayOf())
            Logger.log(
                TAG,
                "notificationCharacteristic ${notificationCharacteristic.uuid} 没有通知权限"
            )
            return
        }
        if (!BleManager.characteristicCanWrite(writeDataCharacteristic)) {
            callback.sendIntercept(0, 0, byteArrayOf())
            return
        }
        if (!enableNotification(address, notificationCharacteristic, true)) {
            callback.sendIntercept(0, 0, byteArrayOf())
            return
        }
        val runnable = Runnable {
            val pageCount = byteArray.getPageCount(singlePackMaxLength)
            val targetIndex = pageCount - 1
            var currentIndex = 0
            var tryCount = 0
            var receiveNotifyTimer: ScheduledThreadPoolExecutor? = null
            var currentSendData: ByteArray? = null
            val cacheListener =
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList.remove(address)
            val listener = object : OnCharacteristicDataOptionsListener {
                override fun onCharacteristicRead(
                    address: String,
                    characteristic: BluetoothGattCharacteristic,
                    value: ByteArray,
                    gattState: Int
                ) {

                }

                override fun onCharacteristicWrite(
                    address: String, characteristic: BluetoothGattCharacteristic, gattState: Int
                ) {
                    if (gattState != BluetoothGatt.GATT_SUCCESS) {
                        GlobalConnectVariable.writeLargeDataKeepList[address] = false
                        InternalConstants.handler.post {
                            callback.writeDataError(
                                currentIndex,
                                targetIndex,
                                gattState,
                                currentSendData ?: byteArrayOf()
                            )
                        }
                        return
                    }
                    InternalConstants.handler.post {
                        callback.sendProgressChanged(
                            currentIndex, targetIndex, currentSendData ?: byteArrayOf()
                        )
                    }
                }

                override fun onCharacteristicNotify(
                    address: String,
                    characteristic: BluetoothGattCharacteristic,
                    value: ByteArray
                ) {
                    if (notificationCharacteristic.uuid.toString() != characteristic.uuid.toString()) {
                        return
                    }
                    InternalConstants.handler.post {
                        val verifySucceed = callback.verifyNotificationData(
                            currentIndex,
                            targetIndex,
                            currentSendData ?: byteArrayOf(),
                            characteristic,
                            value
                        )
                        if (verifySucceed) {
                            currentIndex++
                            GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
                        } else {
                            callback.sendIntercept(
                                currentIndex, targetIndex, currentSendData ?: byteArrayOf()
                            )
                        }
                    }
                }
            }
            GlobalConnectVariable.onCharacteristicDataOptionsListenerList[address] = listener
            GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
            InternalConstants.handler.post {
                callback.sendStarted()
            }
            GlobalConnectVariable.writeLargeDataKeepList[address] = true
            while (true) {
                if (GlobalConnectVariable.writeLargeDataKeepList[address] != true) {
                    break
                }
                if (GlobalConnectVariable.writeLargeDataContinueFlagList[address] != true) {
                    continue
                }
                GlobalConnectVariable.writeLargeDataContinueFlagList[address] = false
                currentSendData =
                    byteArray.getCurrentPackageData(
                        currentIndex,
                        pageCount,
                        singlePackMaxLength
                    )
                if (currentSendData == null) {
                    InternalConstants.handler.post {
                        callback.sendFinish()
                    }
                    break
                }
                val succeed =
                    writeCompatCharacteristicData(
                        address,
                        writeDataCharacteristic,
                        currentSendData
                    )
                if (!succeed) {
                    if (tryCount <= maxSendTryCount) {
                        tryCount++
                        GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
                        continue
                    }
                    InternalConstants.handler.post {
                        callback.sendFailed(currentIndex, targetIndex, currentSendData)
                    }
                    break
                }
                //开启通知接收超时定时器
                receiveNotifyTimer?.shutdownNow()
                receiveNotifyTimer = InternalConstants.newScheduledThreadPoolExecutor()
                receiveNotifyTimer.schedule({
                    val needContinue = callback.waitNotifyTimeout(
                        currentIndex, targetIndex, currentSendData
                    )
                    if (needContinue) {
                        currentIndex++
                        GlobalConnectVariable.writeLargeDataContinueFlagList[address] = true
                    } else {
                        callback.sendIntercept(currentIndex, targetIndex, currentSendData)
                    }
                }, receiveNotificationTimeoutMillis, TimeUnit.MILLISECONDS)
            }
            if (cacheListener != null) {
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList[address] =
                    cacheListener
            } else {
                GlobalConnectVariable.onCharacteristicDataOptionsListenerList.remove(address)
            }
            GlobalConnectVariable.writeLargeDataContinueFlagList.remove(address)
            GlobalConnectVariable.writeLargeDataKeepList.remove(address)
        }
        InternalConstants.threadFactory.newThread(runnable).start()
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param address 设备地址
     * @param writeDataServiceUUID 写入数据的serviceUUID
     * @param writeDataCharacteristicUUID 写入数据的characteristicUUID
     * @param notifyDataServiceUUID 通知数据的serviceUUID
     * @param notifyDataCharacteristicUUID 通知数据的characteristicUUID
     * @param byteArray 写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值20
     * @param maxSendTryCount 最大发送尝试次数,默认值3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值1000,单位:ms
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        writeDataServiceUUID: UUID,
        writeDataCharacteristicUUID: UUID,
        notifyDataServiceUUID: UUID,
        notifyDataCharacteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        val writeDataCharacteristic =
            getCharacteristic(address, writeDataServiceUUID, writeDataCharacteristicUUID)
        val notifyDataCharacteristic =
            getCharacteristic(address, notifyDataServiceUUID, notifyDataCharacteristicUUID)
        if (writeDataCharacteristic == null) {
            Logger.log(TAG, "can not find target characteristic:${writeDataCharacteristicUUID}")
            callback.startFailed()
            return
        }
        if (notifyDataCharacteristic == null) {
            Logger.log(TAG, "can not find target characteristic:${notifyDataCharacteristicUUID}")
            callback.startFailed()
            return
        }
        writeLargeCharacteristicDataWithNotification(
            address,
            writeDataCharacteristic,
            notifyDataCharacteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param address 设备地址
     * @param writeDataServiceUUIDString 写入数据的服务UUID字符串
     * @param writeDataCharacteristicUUIDString 写入数据的特征UUID字符串
     * @param notifyDataServiceUUIDString 通知数据的服务UUID字符串
     * @param notifyDataCharacteristicUUIDString 通知数据的特征UUID字符串
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度.默认值:20
     * @param maxSendTryCount 最大发送尝试次数.默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间.默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        writeDataServiceUUIDString: String,
        writeDataCharacteristicUUIDString: String,
        notifyDataServiceUUIDString: String,
        notifyDataCharacteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        val writeDataCharacteristic =
            getCharacteristic(
                address,
                writeDataServiceUUIDString,
                writeDataCharacteristicUUIDString
            )
        val notifyDataCharacteristic =
            getCharacteristic(
                address,
                notifyDataServiceUUIDString,
                notifyDataCharacteristicUUIDString
            )
        if (writeDataCharacteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic:${writeDataCharacteristicUUIDString}"
            )
            callback.startFailed()
            return
        }
        if (notifyDataCharacteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic:${notifyDataCharacteristicUUIDString}"
            )
            callback.startFailed()
            return
        }
        writeLargeCharacteristicDataWithNotification(
            address,
            writeDataCharacteristic,
            notifyDataCharacteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param address 设备地址
     * @param serviceUUID 服务UUID
     * @param writeDataCharacteristicUUID 写入数据特征UUID
     * @param notifyDataCharacteristicUUID 通知数据特征UUID
     * @param byteArray 写入数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        serviceUUID: UUID,
        writeDataCharacteristicUUID: UUID,
        notifyDataCharacteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            address,
            serviceUUID,
            writeDataCharacteristicUUID,
            serviceUUID,
            notifyDataCharacteristicUUID,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param address 蓝牙地址
     * @param serviceUUIDString 服务UUID字符串
     * @param writeDataCharacteristicUUIDString 写入数据特征UUID字符串
     * @param notifyDataCharacteristicUUIDString 通知数据特征UUID字符串
     * @param byteArray 写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        serviceUUIDString: String,
        writeDataCharacteristicUUIDString: String,
        notifyDataCharacteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            address,
            serviceUUIDString,
            writeDataCharacteristicUUIDString,
            serviceUUIDString,
            notifyDataCharacteristicUUIDString,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param address 蓝牙地址
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        serviceUUID: UUID,
        characteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            address,
            serviceUUID,
            characteristicUUID,
            characteristicUUID,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param address 蓝牙地址
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            address,
            serviceUUIDString,
            characteristicUUIDString,
            characteristicUUIDString,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param address 蓝牙地址
     * @param characteristic 特征
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        address: String,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            address,
            characteristic,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param device 蓝牙设备
     * @param writeDataCharacteristic 写入数据的特征
     * @param notificationCharacteristic 接收通知的特征
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        writeDataCharacteristic: BluetoothGattCharacteristic,
        notificationCharacteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device.address,
            writeDataCharacteristic,
            notificationCharacteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param device 蓝牙设备
     * @param writeDataServiceUUID 写入数据的特征所属的服务
     * @param writeDataCharacteristicUUID 写入数据的特征
     * @param notifyDataServiceUUID 接收通知的特征所属的服务
     * @param notifyDataCharacteristicUUID 接收通知的特征
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        writeDataServiceUUID: UUID,
        writeDataCharacteristicUUID: UUID,
        notifyDataServiceUUID: UUID,
        notifyDataCharacteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        val writeDataCharacteristic =
            getCharacteristic(device, writeDataServiceUUID, writeDataCharacteristicUUID)
        val notifyDataCharacteristic =
            getCharacteristic(device, notifyDataServiceUUID, notifyDataCharacteristicUUID)
        if (writeDataCharacteristic == null) {
            Logger.log(TAG, "can not find target characteristic:${writeDataCharacteristicUUID}")
            callback.startFailed()
            return
        }
        if (notifyDataCharacteristic == null) {
            Logger.log(TAG, "can not find target characteristic:${notifyDataCharacteristicUUID}")
            callback.startFailed()
            return
        }
        writeLargeCharacteristicDataWithNotification(
            device,
            writeDataCharacteristic,
            notifyDataCharacteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param device 设备
     * @param writeDataServiceUUIDString 写入数据的服务UUID字符串
     * @param writeDataCharacteristicUUIDString 写入数据的特征UUID字符串
     * @param notifyDataServiceUUIDString 通知数据的服务UUID字符串
     * @param notifyDataCharacteristicUUIDString 通知数据的特征UUID字符串
     * @param byteArray 写入的数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        writeDataServiceUUIDString: String,
        writeDataCharacteristicUUIDString: String,
        notifyDataServiceUUIDString: String,
        notifyDataCharacteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        val writeDataCharacteristic =
            getCharacteristic(
                device,
                writeDataServiceUUIDString,
                writeDataCharacteristicUUIDString
            )
        val notifyDataCharacteristic =
            getCharacteristic(
                device,
                notifyDataServiceUUIDString,
                notifyDataCharacteristicUUIDString
            )
        if (writeDataCharacteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic:${writeDataCharacteristicUUIDString}"
            )
            callback.startFailed()
            return
        }
        if (notifyDataCharacteristic == null) {
            Logger.log(
                TAG,
                "can not find target characteristic:${notifyDataCharacteristicUUIDString}"
            )
            callback.startFailed()
            return
        }
        writeLargeCharacteristicDataWithNotification(
            device,
            writeDataCharacteristic,
            notifyDataCharacteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param device 设备
     * @param serviceUUID 服务UUID
     * @param writeDataCharacteristicUUID 写入数据特征UUID
     * @param notifyDataCharacteristicUUID 通知数据特征UUID
     * @param byteArray 数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        serviceUUID: UUID,
        writeDataCharacteristicUUID: UUID,
        notifyDataCharacteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device,
            serviceUUID,
            writeDataCharacteristicUUID,
            serviceUUID,
            notifyDataCharacteristicUUID,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param device 蓝牙设备
     * @param serviceUUIDString 服务UUID字符串
     * @param writeDataCharacteristicUUIDString 写入数据特征UUID字符串
     * @param notifyDataCharacteristicUUIDString 通知数据特征UUID字符串
     * @param byteArray 要写入的数据
     * @param callback 回调
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        serviceUUIDString: String,
        writeDataCharacteristicUUIDString: String,
        notifyDataCharacteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device,
            serviceUUIDString,
            writeDataCharacteristicUUIDString,
            serviceUUIDString,
            notifyDataCharacteristicUUIDString,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     *
     * @param device 蓝牙设备
     * @param serviceUUID 服务UUID
     * @param characteristicUUID 特征UUID
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        serviceUUID: UUID,
        characteristicUUID: UUID,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device,
            serviceUUID,
            characteristicUUID,
            characteristicUUID,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param device 蓝牙设备
     * @param serviceUUIDString 服务UUID字符串
     * @param characteristicUUIDString 特征UUID字符串
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        serviceUUIDString: String,
        characteristicUUIDString: String,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device,
            serviceUUIDString,
            characteristicUUIDString,
            characteristicUUIDString,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 写入大量数据-需要处理通知信息
     * @param device 蓝牙设备
     * @param characteristic 特征
     * @param byteArray 要写入的数据
     * @param callback 回调函数
     * @param singlePackMaxLength 单包最大长度,默认值:20
     * @param maxSendTryCount 最大发送尝试次数,默认值:3
     * @param receiveNotificationTimeoutMillis 接收通知超时时间,默认值:1000,单位:毫秒
     */
    fun writeLargeCharacteristicDataWithNotification(
        device: BluetoothDevice,
        characteristic: BluetoothGattCharacteristic,
        byteArray: ByteArray,
        callback: OnLargeCharacteristicDataWriteWithNotificationListener,
        singlePackMaxLength: Int = 20,
        maxSendTryCount: Int = 3,
        receiveNotificationTimeoutMillis: Long = 1000
    ) {
        writeLargeCharacteristicDataWithNotification(
            device.address,
            characteristic,
            byteArray,
            callback,
            singlePackMaxLength,
            maxSendTryCount,
            receiveNotificationTimeoutMillis
        )
    }

    /**
     * 执行可靠数据写入
     * @param address 蓝牙设备地址
     * @return 是否成功
     */
    fun executeReliableWrite(address: String): Boolean {
        val result = GlobalConnectVariable.gattList[address]?.executeReliableWrite() ?: false
        Logger.log(TAG, "$address 执行可靠数据写入 result $result")
        return result
    }

    /**
     * 执行可靠数据写入
     * @param device 蓝牙设备
     * @return 是否成功
     */
    fun executeReliableWrite(device: BluetoothDevice): Boolean {
        return executeReliableWrite(device.address)
    }

    /**
     * 取消可靠数据写入
     * @param address 蓝牙设备地址
     * @return 是否成功
     */
    fun abortReliableWrite(address: String): Boolean {
        val gatt = GlobalConnectVariable.gattList[address]
        gatt?.abortReliableWrite()
        val result = gatt != null
        Logger.log(TAG, "$address 取消可靠数据写入 result $result")
        return result
    }

    /**
     * 取消可靠数据写入
     * @param device 蓝牙设备
     * @return 是否成功
     */
    fun abortReliableWrite(device: BluetoothDevice): Boolean {
        return abortReliableWrite(device.address)
    }

    /**
     * 开启可靠数据写入
     * @param address 蓝牙设备地址
     * @return 是否成功
     */
    fun beginReliableWrite(address: String): Boolean {
        val result = GlobalConnectVariable.gattList[address]?.beginReliableWrite() ?: false
        Logger.log(TAG, "$address 开启可靠数据写入 result $result")
        return result
    }

    /**
     * 开启可靠数据写入
     * @param device 蓝牙设备
     * @return 是否成功
     */
    fun beginReliableWrite(device: BluetoothDevice): Boolean {
        return beginReliableWrite(device.address)
    }

    /**
     * 读取远程设备的RSSI
     * @param address 蓝牙设备地址
     * @return 是否成功
     */
    fun readRemoteRssi(address: String): Boolean {
        return GlobalConnectVariable.gattList[address]?.readRemoteRssi() ?: false
    }

    /**
     * 读取远程设备的RSSI
     * @param device 蓝牙设备
     * @return 是否成功
     */
    fun readRemoteRssi(device: BluetoothDevice): Boolean {
        return readRemoteRssi(device.address)
    }

    /**
     * 请求变更MTU
     * @param address 蓝牙设备地址
     * @param tryTarget 目标MTU值
     * @return 是否成功（仅仅表示请求发送成功，实际的MTU值需要在相关回调中获取）
     */
    fun requestMtu(address: String, tryTarget: Int): Boolean {
        return GlobalConnectVariable.gattList[address]?.requestMtu(tryTarget) ?: false
    }

    /**
     * 请求变更MTU
     * @param device 蓝牙设备
     * @param tryTarget 目标MTU值
     * @return 是否成功（仅仅表示请求发送成功，实际的MTU值需要在相关回调中获取）
     */
    fun requestMtu(device: BluetoothDevice, tryTarget: Int): Boolean {
        return requestMtu(device.address, tryTarget)
    }

    /**
     * 读取phy
     * @param address 蓝牙设备地址
     * @return 是否成功
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun readPhy(address: String): Boolean {
        val gatt = GlobalConnectVariable.gattList[address]
        gatt?.readPhy()
        val result = gatt != null
        Logger.log(TAG, "$address 读取phy result $result")
        return result
    }

    /**
     * 读取phy
     * @param device 蓝牙设备
     * @return 是否成功
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun readPhy(device: BluetoothDevice): Boolean {
        return readPhy(device.address)
    }

    /**
     * 设置phy
     * @param address 蓝牙设备地址
     * @param txPhy 传输phy
     * @param rxPhy 接收phy
     * @param blePhyOptions 蓝牙phy选项
     * @return 是否成功
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun setPreferredPhy(
        address: String, txPhy: BlePhy, rxPhy: BlePhy, blePhyOptions: BlePhyOptions
    ): Boolean {
        if (txPhy == BlePhy.UNKNOWN_PHY || rxPhy == BlePhy.UNKNOWN_PHY) {
            return false
        }
        val gatt = GlobalConnectVariable.gattList[address]
        gatt?.setPreferredPhy(txPhy.value, rxPhy.value, blePhyOptions.value)
        val result = gatt != null
        Logger.log(TAG, "address $address 设置phy result $result")
        return result
    }

    /**
     * 设置phy
     * @param device 蓝牙设备
     * @param txPhy 传输phy
     * @param rxPhy 接收phy
     * @param blePhyOptions 蓝牙phy选项
     * @return 是否成功
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun setPreferredPhy(
        device: BluetoothDevice, txPhy: BlePhy, rxPhy: BlePhy, blePhyOptions: BlePhyOptions
    ): Boolean {
        return setPreferredPhy(device.address, txPhy, rxPhy, blePhyOptions)
    }

    /**
     * 刷新 GATT 缓存.
     * 注意:部分自定义系统返回true但不生效。到目前为止还没有解决方案
     *
     * @param address 蓝牙设备地址
     * @return true 表示刷新成功
     */
    fun refreshGattCache(address: String): Boolean {
        val bluetoothGatt = GlobalConnectVariable.gattList[address] ?: return false
        try {
            val refresh: Method = bluetoothGatt.javaClass.getMethod("refresh")
            return refresh.invoke(bluetoothGatt) as Boolean
        } catch (e: NoSuchMethodException) {
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
        return false
    }


    /**
     * 刷新 GATT 缓存.
     * 注意:部分自定义系统返回true但不生效。到目前为止还没有解决方案
     *
     * @param device 蓝牙设备
     * @return true 表示刷新成功
     */
    fun refreshGattCache(device: BluetoothDevice): Boolean {
        return refreshGattCache(device.address)
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 私有方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 创建GATT
     * @param device 蓝牙设备
     * @param autoConnect 自动连接
     * @param transport 传输方式
     * @param phyMask 物理层掩码
     * @param handler 回调处理器
     */
    private fun createGatt(
        device: BluetoothDevice,
        autoConnect: Boolean = false,
        transport: BleConnectTransport? = null,
        phyMask: BleConnectPhyMask? = null,
        handler: Handler? = null
    ): BluetoothGatt? {
        val bluetoothGatt = GlobalConnectVariable.gattList.remove(device.address)
        if (bluetoothGatt != null) {
            bluetoothGatt.close()
            return bluetoothGatt
        }
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            device.connectGatt(
                InternalConstants.context,
                autoConnect,
                defaultMultiBluetoothGattCallback,
                transport?.value ?: BleConnectTransport.TRANSPORT_AUTO.value,
                phyMask?.value ?: BleConnectPhyMask.PHY_LE_1M_MASK.value,
                handler
            )
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            device.connectGatt(
                InternalConstants.context,
                autoConnect,
                defaultMultiBluetoothGattCallback,
                transport?.value ?: BleConnectTransport.TRANSPORT_AUTO.value
            )
        } else {
            device.connectGatt(
                InternalConstants.context, autoConnect, defaultMultiBluetoothGattCallback
            )
        }
    }
}